package com.atguigu.servicebase.responsibilityLinkHandler;

/**
 * @author lwh
 * @description:
 * @date 2023/1/31 9:28
 */

import org.springframework.core.annotation.Order;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class BizHandlerChain<T> {
    private List<AbstractBizHandler> bizHandlers = new ArrayList<>();
    private AbstractBizHandler header = null;
    private AbstractBizHandler tail = null;
    private AbstractBizHandler noOrder = null;

    private BizHandlerChain(Class<? extends AbstractBizHandler> handlerClazz) {
        Map<String, ? extends AbstractBizHandler> handlerMap = ApplicationContextUtils.getApplicationContext().getBeansOfType(handlerClazz);
        for (AbstractBizHandler handler : handlerMap.values()) {
            this.sort(handler);
        }

        if (this.tail != null) {
            this.tail.setNextHandler(null);
        }

        if (this.header == null && this.noOrder != null) {
            this.header = noOrder;
        } else if (this.header != null && this.noOrder != null) {
            this.tail.setNextHandler(noOrder);
        }
    }

    private BizHandlerChain(List<AbstractBizHandler> bizHandlers) {
        this.setBizHandlers(bizHandlers);
    }

    public void setBizHandlers(List<AbstractBizHandler> bizHandlers) {
        for (int i = 0; i < bizHandlers.size(); i++) {
            AbstractBizHandler bizHandler = bizHandlers.get(i);
            if (bizHandlers.size() >= (i+1)) {
                bizHandler.setNextHandler(null);
            } else {
                bizHandler.setNextHandler(bizHandlers.get(i+1));
            }
        }
        this.bizHandlers = bizHandlers;

        if (bizHandlers.size() > 0) {
            this.header = bizHandlers.get(0);
        }
    }

    public static BizHandlerChain newInstance(List<AbstractBizHandler> bizHandlers) {
        return new BizHandlerChain(bizHandlers);
    }

    public static BizHandlerChain newInstance(Class<? extends AbstractBizHandler> handlerClazz) {
        return new BizHandlerChain(handlerClazz);
    }

    public void start(T args) {
        if (header != null) {
            header.handleBizLogic(args);
        }
    }

    private void sort(AbstractBizHandler handler) {
        if (handler == null) {
            return;
        }
        // 处理没设置序列的处理器
        Order orderAnno = handler.getClass().getAnnotation(Order.class);
        if (orderAnno == null) {
            if (noOrder == null) {
                noOrder = handler;
            } else {
                noOrder.setNextHandler(handler);
            }
            return;
        }
        // 初始化链表指针
        if (this.header == null) {
            this.header = handler;
            this.tail = handler;
            return;
        }

        this.insertHandler(this.header, this.header.getNextHandler(), handler);
    }

    private void insertHandler(AbstractBizHandler preHandler, AbstractBizHandler nextHandler, AbstractBizHandler curHandler) {
        int curOrder = curHandler.getClass().getAnnotation(Order.class).value();
        int preOrder = preHandler.getClass().getAnnotation(Order.class).value();

        if (nextHandler == null) {
            if (curOrder < preOrder) {
                curHandler.setNextHandler(preHandler);
                this.tail = preHandler;
            } else {
                preHandler.setNextHandler(curHandler);
                this.tail = curHandler;
            }
        } else {
            int nextOrder = nextHandler.getClass().getAnnotation(Order.class).value();
            if (curOrder > preOrder && curOrder < nextOrder) {
                preHandler.setNextHandler(curHandler);
                curHandler.setNextHandler(nextHandler);
            } else if (curOrder >= nextOrder ){
                this.insertHandler(nextHandler, nextHandler.getNextHandler(), curHandler);
            } else if (curOrder <= preOrder) {
                curHandler.setNextHandler(preHandler);
            }
        }

        if (curOrder < preOrder && preHandler == this.header) {
            this.header = curHandler;
        }
    }

}